package cn.anecansaitin.not_enough_harness.common.harness_data;

import cn.anecansaitin.not_enough_harness.common.ModDataMap;
import cn.anecansaitin.not_enough_harness.common.item.ModComponents;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.function.Supplier;

public record HarnessSpeed(float forwardSpeed, float backwardSpeed, float leftSpeed, float rightSpeed,
                           float upSpeed, float downSpeed) {
    public static final HarnessSpeed ZERO = new HarnessSpeed(0, 0);

    public static final Codec<HarnessSpeed> CODEC =
            RecordCodecBuilder.create(instance ->
                    instance.group(
                                    Codec.FLOAT.fieldOf("forward_speed").forGetter(HarnessSpeed::forwardSpeed),
                                    Codec.FLOAT.fieldOf("backward_speed").forGetter(HarnessSpeed::backwardSpeed),
                                    Codec.FLOAT.fieldOf("left_speed").forGetter(HarnessSpeed::leftSpeed),
                                    Codec.FLOAT.fieldOf("right_speed").forGetter(HarnessSpeed::rightSpeed),
                                    Codec.FLOAT.fieldOf("up_speed").forGetter(HarnessSpeed::upSpeed),
                                    Codec.FLOAT.fieldOf("down_speed").forGetter(HarnessSpeed::downSpeed)
                            )
                            .apply(instance, HarnessSpeed::new)
            );

    public static final Codec<HarnessSpeed> SYNC_CODEC =
            Codec.list(Codec.FLOAT, 6, 6)
                 .comapFlatMap(
                         floats -> {
                             DataResult<List<Float>> result;

                             if (floats.size() == 6) {
                                 result = DataResult.success(floats);
                             } else {
                                 Supplier<String> supplier = () -> "Input is not a list of 6 longs";
                                 result = DataResult.error(supplier, floats);
                             }

                             return result.map(floats1 -> new HarnessSpeed(floats1.getFirst(), floats1.get(1), floats1.get(2), floats1.get(3), floats1.get(4), floats1.get(5)));
                         },
                         data -> List.of(data.forwardSpeed, data.backwardSpeed, data.leftSpeed, data.rightSpeed, data.upSpeed, data.downSpeed)
                 );

    public static final StreamCodec<FriendlyByteBuf, HarnessSpeed> STREAM_CODEC =
            StreamCodec.composite(
                    ByteBufCodecs.FLOAT, HarnessSpeed::forwardSpeed,
                    ByteBufCodecs.FLOAT, HarnessSpeed::backwardSpeed,
                    ByteBufCodecs.FLOAT, HarnessSpeed::leftSpeed,
                    ByteBufCodecs.FLOAT, HarnessSpeed::rightSpeed,
                    ByteBufCodecs.FLOAT, HarnessSpeed::upSpeed,
                    ByteBufCodecs.FLOAT, HarnessSpeed::downSpeed,
                    HarnessSpeed::new
            );

    public HarnessSpeed(float horizontalSpeed, float verticalSpeed) {
        this(horizontalSpeed, horizontalSpeed, horizontalSpeed, horizontalSpeed, verticalSpeed, verticalSpeed);
    }

    @NotNull
    public static HarnessSpeed getComponentOrDataMapAndSet(ItemStack item) {
        HarnessSpeed harnessSpeed = item.get(ModComponents.HARNESS_SPEED);

        if (harnessSpeed == null) {
            HarnessSpeed dataMap = item.getItemHolder().getData(ModDataMap.HARNESS_SPEED);

            if (dataMap == null) {
                dataMap = HarnessSpeed.ZERO;
            }

            item.set(ModComponents.HARNESS_SPEED, dataMap);
            return dataMap;
        }

        return harnessSpeed;
    }
}
